Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

properly escape quotes in passwords by calling to_ruby #1189

Merged
merged 1 commit into from
Oct 18, 2024

Conversation

evgeni
Copy link
Member

@evgeni evgeni commented Oct 16, 2024

database passwords can contain special characters, especially " and '
so we can't just print the value of the field enclosed by double quotes
as that would break whenever the user uses a literal " in their password

using to_ruby here and not to_yaml, as the former gives us correct escaping
without the whole --- and \n enclosing that to_yaml forces.
using to_yaml would require to pass the whole config hash to it

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized this also goes for the pulpcore PR I already merged

@@ -30,6 +30,6 @@
username: <%= $username %>
<% } -%>
<% if $password { -%>
password: "<%= $password %>"
password: <%= stdlib::to_ruby($password) %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my phone so tricky to check, but can this be a Sensitive and does it handle that well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, it can. No idea how to test this tho 🙈

In pulpcore, we're lucky, it's a String.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can pass Sensitive to epp and it will automatically unwrap it, so that's fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test, let's see

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol. init.pp says db_password is a String, while the epp file allows Sensitive[String]:

String[1] $db_password = $foreman::params::db_password,

Variant[Undef, String[1], Sensitive[String[1]]] $password,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

going to drop the test (as it's failing now) and add sensitive support later

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1190 says this does not work for Sensitive

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this not even works properly, what the hell

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I'm stupid, I was running a non-patched installer 🙈

database passwords can contain special characters, especially " and '
so we can't just print the value of the field enclosed by double quotes
as that would break whenever the user uses a literal " in their password

using to_ruby here and not to_yaml, as the former gives us correct escaping
without the whole `---` and `\n` enclosing that to_yaml forces.
using to_yaml would require to pass *the whole* config hash to it
@evgeni evgeni marked this pull request as draft October 18, 2024 11:15
@evgeni evgeni marked this pull request as ready for review October 18, 2024 11:16
@alexjfisher
Copy link
Contributor

to_ruby? Does this really work with all inputs? Don't you need something with specific yaml knowledge?

It'd be a stupid password, but if your password was previously the string no, it would have been correctly quoted. Now it wouldn't be and yaml would treat it as a boolean.

@alexjfisher
Copy link
Contributor

to_ruby? Does this really work with all inputs? Don't you need something with specific yaml knowledge?

It'd be a stupid password, but if your password was previously the string no, it would have been correctly quoted. Now it wouldn't be and yaml would treat it as a boolean.

or maybe it will be quoted actually. Just looks a bit funky.

@evgeni
Copy link
Member Author

evgeni commented Oct 18, 2024

It does work, partially by accident (don't look at the implementation in stdlib).

Yes to_yaml would be better, but that requires more work as then we need to generate the whole hash with it.

@alexjfisher
Copy link
Contributor

to_yaml for the whole file would have its advantages, but you wouldn't be able to include the comments you currently do.

I'm thinking a new stdlib function just for escaping strings in a yaml specific way would be beneficial. Something that uses the low level Psych API.

For a PoC...

require 'psych'
require 'stringio'

def string_to_yaml_escaped_string(str)
  out = StringIO.new
  emitter = Psych::Emitter.new(out)

  emitter.start_stream(Psych::Nodes::Stream::UTF8)
  emitter.start_document([], [], true) # implicit flag set to true to suppress document start marker

  emitter.scalar(
    str,
    nil,
    nil,
    false,
    true,
    Psych::Nodes::Scalar::DOUBLE_QUOTED
  )

  emitter.end_document(true) # implicit flag set to true to suppress document end marker
  emitter.end_stream

  out.string
end

str = 'ao&"$bc\ndef'
puts string_to_yaml_escaped_string(str)

@ekohl
Copy link
Member

ekohl commented Oct 18, 2024

I had hoped there was some flag to omit the document header and an easier API to write out fragments. This doesn't deal with any datastructure, does it?

@alexjfisher
Copy link
Contributor

I had hoped there was some flag to omit the document header and an easier API to write out fragments. This doesn't deal with any datastructure, does it?

Unfortunately, it looks like you've got to use the low level API to get this control. YAML scalars are strings and numbers, not arrays and hashes, so this would only really be useful for safely encoding individual strings. You could make the style configurable though using a different style constant from this list. https://docs.ruby-lang.org/en/master/Psych/Nodes/Scalar.html

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in the short term this is good enough. If we need to wait for a new stdlib function it'll take too long before it's really available and I expect this will simply always quote strings instead of sometimes, which I actually prefer. The bare strings that sometimes turn into booleans or other data types scare me.

@ekohl ekohl merged commit d14ae8b into master Oct 18, 2024
19 checks passed
@ekohl ekohl deleted the escape-passwords branch October 18, 2024 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants